package com.yixing.tech.system.service.impl;

import org.apache.commons.lang3.StringUtils;
import com.yixing.tech.common.base.BaseMongoDao;
import com.yixing.tech.common.base.BusinessException;
import com.yixing.tech.common.base.Page;
import com.yixing.tech.common.base.PageRow;
import com.yixing.tech.common.enums.ComparisonSymbol;
import com.yixing.tech.common.enums.DepartmentRole;
import com.yixing.tech.system.dao.DepartmentDao;
import com.yixing.tech.system.po.Department;
import com.yixing.tech.system.service.IDepartmentService;
import com.yixing.tech.common.utils.CommonUtil;
import com.yixing.tech.common.utils.DataUtil;
import com.yixing.tech.common.vo.s3.DepartmentVO;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.schema.JsonSchemaObject;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author yixing tech
 * at 2021/12/20
 * describe：
 */
@Service
@Slf4j
public class DepartmentServiceImpl implements IDepartmentService {
    @Resource
    private BaseMongoDao baseMongoDao;
    @Resource
    private MongoTemplate mongoTemplate;
    @Resource
    private DepartmentDao departmentDao;

    @Value("${official-tenant-id}")
    private String officialTenantId;

    @Override
    public void add(DepartmentVO dictVO) throws BusinessException {
        Department dict = DataUtil.o2o(dictVO, Department.class);
        dict.setId(null);
        baseMongoDao.save(dict);

    }

    @Override
    public void batchAdd(List<DepartmentVO> list) throws BusinessException {

    }

    @Override
    public DepartmentVO queryById(String id) {
        List<AggregationOperation> operations = new ArrayList<>();

        Criteria criteria = Criteria.where("_id").is(new ObjectId(id));
        operations.add(Aggregation.match(criteria));
        operations.add(Aggregation.lookup("user", "supervisor._id", "_id", "supervisor"));
        operations.add(Aggregation.unwind("supervisor", true));
//        operations.add(Aggregation.addFields().addFieldWithValue("supervisor.id", ConvertOperators.Convert.convertValue("$supervisor._id").to(JsonSchemaObject.Type.STRING)).build());

        operations.add(Aggregation.lookup("user", "leader._id", "_id", "leader"));
        operations.add(Aggregation.unwind("leader", true));
//        operations.add(Aggregation.addFields().addFieldWithValue("leader.id", ConvertOperators.Convert.convertValue("$leader._id").to(JsonSchemaObject.Type.STRING)).build());
        Aggregation agg = Aggregation.newAggregation(operations);
        AggregationResults<DepartmentVO> results = mongoTemplate.aggregate(agg, "department", DepartmentVO.class);
        List<DepartmentVO> list = results.getMappedResults();
        if (CommonUtil.listIsBlank(list)) return null;
        return list.get(0);
    }

    @Override
    public List<DepartmentVO> queryByIds(List<String> ids) {
        return null;
    }

    @Override
    public DepartmentVO queryByCondition(DepartmentVO dictVO) throws BusinessException {
        return null;
    }

    @Override
    public void update(DepartmentVO dictVO) throws BusinessException {
        baseMongoDao.update(DataUtil.o2o(dictVO, Department.class));
        String parentId = dictVO.getParentId();
        if (!StringUtils.isEmpty(parentId)) {
            departmentDao.addExistedChild(parentId, dictVO.getId());
        }


    }

    @Override
    public Page<DepartmentVO> list(PageRow<DepartmentVO> pageRow) {
        String parentId = pageRow.getCondition().getParentId();
        if (StringUtils.isEmpty(parentId)) {
            pageRow.getCondition().putComparisonSymbols("parentId", ComparisonSymbol.isNull);
        }
        List<AggregationOperation> operations = new ArrayList<>();
        Criteria criteria = baseMongoDao.condition2Criteria(pageRow.getCondition());
        operations.add(Aggregation.match(criteria));

        SkipOperation skipOperation = Aggregation.skip(Long.valueOf(pageRow.getPageNo() * pageRow.getPageSize()));
        operations.add(skipOperation);

        LimitOperation limitOperation = Aggregation.limit(pageRow.getPageSize());
        operations.add(limitOperation);

        operations.add(Aggregation.lookup("user", "supervisor._id", "_id", "supervisor"));
        operations.add(Aggregation.unwind("supervisor", true));
//        operations.add(Aggregation.addFields().addFieldWithValue("supervisor.id", ConvertOperators.Convert.convertValue("$supervisor._id").to(JsonSchemaObject.Type.STRING)).build());

        operations.add(Aggregation.lookup("user", "leader._id", "_id", "leader"));
        operations.add(Aggregation.unwind("leader", true));
//        operations.add(Aggregation.addFields().addFieldWithValue("leader.id", ConvertOperators.Convert.convertValue("$leader._id").to(JsonSchemaObject.Type.STRING)).build());

        List<DepartmentVO> l = baseMongoDao.aggregate(operations, "department", DepartmentVO.class).getMappedResults();
        long count = baseMongoDao.count(criteria, Department.class);
        findChildren(l);
        return new Page<>(l, pageRow.getPageSize(), pageRow.getPageNo() + 1, count);


    }

    @Override
    public List<DepartmentVO> list(DepartmentVO condition) {
        String parentId = condition.getParentId();
        if (StringUtils.isEmpty(parentId)) {
            condition.putComparisonSymbols("parentId", ComparisonSymbol.isNull);
        }

        List<AggregationOperation> operations = new ArrayList<>();

        operations.add(Aggregation.lookup("user", "supervisor._id", "_id", "supervisor"));
        operations.add(Aggregation.unwind("supervisor", true));
        operations.add(Aggregation.addFields().addFieldWithValue("supervisor.id", ConvertOperators.Convert.convertValue("$supervisor._id").to(JsonSchemaObject.Type.STRING)).build());

        operations.add(Aggregation.lookup("user", "leader._id", "_id", "leader"));
        operations.add(Aggregation.unwind("leader", true));
        operations.add(Aggregation.addFields().addFieldWithValue("leader.id", ConvertOperators.Convert.convertValue("$leader._id").to(JsonSchemaObject.Type.STRING)).build());


        Criteria criteria = baseMongoDao.condition2Criteria(condition);
        operations.add(Aggregation.match(criteria));
        List<DepartmentVO> l = baseMongoDao.aggregate(operations, "department", DepartmentVO.class).getMappedResults();
        findChildren(l);
        return l;
    }

    private void findChildren(List<DepartmentVO> parent) {
        for (DepartmentVO vo : parent) {
            if (!CommonUtil.listIsBlank(vo.getChildren())) {
                DepartmentVO cond = new DepartmentVO();
                cond.setParentId(vo.getId());
                cond.setTenantId(vo.getTenantId());
                List<DepartmentVO> children = list(cond);
                if (!children.isEmpty())
                    vo.setChildren(children);
            } else vo.setChildren(null);

        }
    }


    @Override
    public void deleteById(String id) throws BusinessException {
        Department vo = baseMongoDao.get(id, Department.class);
        baseMongoDao.delete(id, Department.class);
        mongoTemplate.remove(Query.query(Criteria.where("parentId").is(id)), Department.class);
        //从父里删除
        String parentId = vo.getParentId();
        if (!StringUtils.isEmpty(parentId)) {
            departmentDao.deleteChild(parentId, vo.getId());
        }
    }

    @Override
    public void delete(List<String> ids) throws BusinessException {

    }

    @Override
    public void addChild(DepartmentVO vo) throws BusinessException {
        departmentDao.addChild(vo);
    }

    @Override
    public List<Map> getRoles() {
        DepartmentRole[] roles = DepartmentRole.values();
        List<Map> list = new ArrayList<>();
        for (DepartmentRole role : roles) {
            Map map = new HashMap(2);
            map.put("key", role.name());
            map.put("value", role.getDesc());
            list.add(map);
        }
        return list;
    }
}
